package com.world.cat.service.generate;

import com.world.common.enums.permission.PrivilegeResourceType;
import com.world.common.util.ExcelUtil;
import com.world.common.util.SysUtil;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.*;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by xinyu.qiu on 2015/7/10.
 */
public class CodeTemplateUtil {
    /**
     * 构造一个对象
     *
     * @param toClazz
     * @param toClazzName
     * @param fromClass
     * @param fromClazzName
     */
    public static void printSetInfo(Class toClazz, String toClazzName, Class fromClass, String fromClazzName) {
        Method[] toMethods = toClazz.getMethods();

        Set<String> toSetNames = new HashSet<>();
        for (Method method : toMethods) {
            String className = method.getName();
            if (className.startsWith("set")) {
                toSetNames.add(className.substring(3));
            }
        }
        Set<String> fromGetNames = new HashSet<>();
        Method[] fromMethods = fromClass.getMethods();
        for (Method method : fromMethods) {
            String className = method.getName();
            if (className.startsWith("get")) {
                fromGetNames.add(className.substring(3));
            }
        }
        System.out.println(toClazz.getSimpleName() + " " + toClazzName + " = new " + toClazz.getSimpleName() + "();");
        for (String setMethodStr : toSetNames) {
            if (fromGetNames.contains(setMethodStr)) {
                System.out.println(toClazzName + ".set" + setMethodStr + "(" + fromClazzName + ".get" + setMethodStr + "());");
            } else {
                System.out.println(toClazzName + ".set" + setMethodStr + "(null);");
            }
        }
    }

    /**
     * printResource(xxController.Class) 导出这个controller的权限。
     *
     * @param controllerClass
     */
    public static void printResource(Class controllerClass) {
        RequestMapping baseRequestMapping = (RequestMapping) controllerClass.getAnnotation(RequestMapping.class);
        String baseURI_prefix = null;
        String baseName = null;
        if (baseRequestMapping != null && ArrayUtils.isNotEmpty(baseRequestMapping.value())) {
            baseURI_prefix = baseRequestMapping.value()[0];
            baseName = baseRequestMapping.name();
        }
        if (baseURI_prefix == null) {
            baseURI_prefix = "";
        }
        Method[] methods = controllerClass.getMethods();
        List<List<String>> result = new ArrayList<>();
        if (ArrayUtils.isNotEmpty(methods)) {
            for (Method method : methods) {
                RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
                ResponseBody responseBody = method.getAnnotation(ResponseBody.class);
                String fullClassName = controllerClass.getName();
                String domainName = fullClassName.split("\\.")[2];
                List<String> resources = new ArrayList<>();


                if (requestMapping != null) {
                    //资源名称	              资源类型	    key	                                                资源URI	                      所属域	    所属模块	             一级菜单	二级菜单	关联菜单key
                    String methodURI = baseURI_prefix + (ArrayUtils.isNotEmpty(requestMapping.value()) ? requestMapping.value()[0] : "");
                    String methodName = requestMapping.name();
                    String key = domainName + "_request_" + (methodURI.startsWith("/") ? methodURI.replaceFirst("/", "").replace("/", "_") : methodURI.replace("/", "_"));
                    if (StringUtils.isNotEmpty(methodName)) {
                        resources.add(baseName + methodName);
                    } else {
                        resources.add("资源名称内容");
                    }
                    resources.add("请求");
                    resources.add(key);
                    resources.add(methodURI);
//                    resources.add(SystemDomain.getEnumByName(domainName.toUpperCase()) == null ? "所属域" : SystemDomain.getEnumByName(domainName.toUpperCase()).getName());
                    resources.add("所属模块");
                    if (responseBody == null) {
                        resources.add("一级菜单");
                        resources.add("二级菜单");
                        resources.add("关联菜单key");
                    } else {
                        resources.add("");
                        resources.add("");
                        resources.add("");
                    }
                    result.add(resources);
                }
            }
        }

        for (List<String> resources : result) {
            for (String str : resources) {
                System.out.print(str);
                System.out.print("\t");
            }
            System.out.println("");
        }
    }

    /**
     * excel2003，按照如下格式填写，生成entity字段，set get方法，jpa配置文件
     * 类型	字段key	描述	数据库字段类型	default
     * String	customerCode	卖家编码,保证唯一,必填	varchar(100)	1
     *
     * @param filePath
     * @param clazz
     */
    public static void generateEntityFromXLS(String filePath, Class clazz) {
        /*try {
            List<String[]> itemList = ExcelUtil.importExcelFromPath(filePath, 1, -1);
            generateEntity(itemList, clazz);
        } catch (Exception e) {
            e.printStackTrace();
        }*/
    }

    //从当前class生成代码:注释要写在字段后面才有效，String的数据库类型默认为varchar(100)，需要自己修改
    //例子 private String priceMemo;//特殊价格
    public static void generateEntityFromClass(Class clazz) {
        String fullFilePath = clazz.getResource("").getPath().substring(1) + clazz.getSimpleName() + ".java";
        try {
            fullFilePath = URLDecoder.decode(fullFilePath,"utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        fullFilePath = fullFilePath.replace("target/classes", "src/main/java");
        fullFilePath = fullFilePath.replace("/", File.separator);
        Field[] fields = clazz.getDeclaredFields();
        Map<String, Class> fieldMap = new HashMap<>();
        for (Field field : fields) {
            fieldMap.put(field.getType().getSimpleName(), field.getType());
        }
        try {
            String encoding = "UTF-8";
            File file = new File(fullFilePath);
            if (file.isFile() && file.exists()) {
                InputStreamReader read = new InputStreamReader(new FileInputStream(file), encoding);//考虑到编码格式
                BufferedReader bufferedReader = new BufferedReader(read);
                String lineTxt = null;
                List<String[]> itemList = new ArrayList<>();
                while ((lineTxt = bufferedReader.readLine()) != null) {
                    if (SysUtil.isNotEmpty(lineTxt)) {
                        lineTxt = lineTxt.trim();
                        int semiIndex = lineTxt.indexOf(";");
                        if (semiIndex != -1) {
                            String fieldStr = lineTxt.substring(0, semiIndex);
                            String commentStr = lineTxt.substring(semiIndex).trim();
                            if (SysUtil.isNotEmpty(commentStr) && commentStr.length() > 3) {
                                commentStr = commentStr.substring(3).trim();
                            } else {
                                commentStr = "";
                            }
                            if (lineTxt.startsWith("private")) {
                                String[] items = fieldStr.split(" ");
                                String[] resultItems = new String[5];
                                int k = 0;
                                for (int i = 1; i < items.length; i++) {
                                    if (StringUtils.isNotEmpty(items[i])) {
                                        resultItems[k] = items[i];
                                        k++;
                                        if (k == 2) {
                                            resultItems[2] = commentStr;
                                            String fieldType = resultItems[0];
                                            if (fieldType.equals(String.class.getSimpleName())) {
                                                resultItems[3] = "varchar(100)";
                                            } else if (fieldType.equals(Long.class.getSimpleName())) {
                                                resultItems[3] = "bigint";
                                            } else if (fieldType.equals(Double.class.getSimpleName())) {
                                                resultItems[3] = "double";
                                            } else if (fieldType.equals(Integer.class.getSimpleName())) {
                                                resultItems[3] = "int";
                                            } else {
                                                Class fieldClass = fieldMap.get(fieldType);
                                                if (fieldClass != null && fieldClass.isEnum()) {
                                                    resultItems[3] = "varchar(50)";
                                                }
                                            }
                                        }
                                    }
                                }
                                itemList.add(resultItems);
                            }
                        }
                    }
                }
                generateEntity(itemList, clazz);
                printToDTO(itemList, clazz, true);
                printFromDTO(itemList, clazz);
                read.close();
            } else {
                System.out.println("找不到指定的文件");
            }
        } catch (Exception e) {
            System.out.println("读取文件内容出错");
            e.printStackTrace();
        }
    }

    //从剪切板生成代码：要求选中并复制字段
    public static void generateEntityFromClipboard(Class clazz) {
        try {
            String codeFrament = getSystemClipboard();
            if (SysUtil.isNotEmpty(codeFrament) && codeFrament.contains("private")) {
                String[] lineTxts = codeFrament.split("\n");
                List<String[]> itemList = new ArrayList<>();
                for (String lineTxt : lineTxts) {
                    if (SysUtil.isNotEmpty(lineTxt)) {
                        lineTxt = lineTxt.trim();
                        int semiIndex = lineTxt.indexOf(";");
                        if (semiIndex != -1) {
                            String fieldStr = lineTxt.substring(0, semiIndex);
                            String commentStr = lineTxt.substring(semiIndex).trim();
                            if (SysUtil.isNotEmpty(commentStr) && commentStr.length() > 3) {
                                commentStr = commentStr.substring(3).trim();
                            } else {
                                commentStr = "";
                            }
                            if (lineTxt.startsWith("private")) {
                                String[] items = fieldStr.split(" ");
                                String[] resultItems = new String[5];
                                int k = 0;
                                for (int i = 1; i < items.length; i++) {
                                    if (StringUtils.isNotEmpty(items[i])) {
                                        resultItems[k] = items[i];
                                        k++;
                                        if (k == 2) {
                                            resultItems[2] = commentStr;
                                            String fieldType = resultItems[0];
                                            if (fieldType.equals(String.class.getSimpleName())) {
                                                resultItems[3] = "varchar(100)";
                                            } else if (fieldType.equals(Long.class.getSimpleName())) {
                                                resultItems[3] = "bigint";
                                            } else if (fieldType.equals(Double.class.getSimpleName())) {
                                                resultItems[3] = "double";
                                            } else if (fieldType.equals(Integer.class.getSimpleName())) {
                                                resultItems[3] = "int";
                                            }
                                        }
                                    }
                                }
                                itemList.add(resultItems);
                            }
                        }
                    }
                }
                generateEntity(itemList, clazz);
                printToDTO(itemList, clazz, false);
                printFromDTO(itemList, clazz);
            } else {
                System.out.println("无效剪切板数据");
            }
        } catch (Exception e) {
            System.out.println("读取剪切板内容出错");
            e.printStackTrace();
        }
    }

    /**
     * excel2003，按照如下格式填写，生成entity字段，set get方法，jpa配置文件
     * 类型	字段key	描述	数据库字段类型	default
     * String	customerCode	卖家编码,保证唯一,必填	varchar(100)	1
     *
     * @param itemList
     * @param clazz
     */
    private static void generateEntity(List<String[]> itemList, Class clazz) {
        Set<String> baseType = new HashSet<>();
        baseType.add(String.class.getSimpleName());
        baseType.add(Long.class.getSimpleName());
        baseType.add(Double.class.getSimpleName());
        baseType.add(Integer.class.getSimpleName());
        baseType.add(Boolean.class.getSimpleName());
        baseType.add(Byte.class.getSimpleName());
        baseType.add(Float.class.getSimpleName());
        baseType.add(Character.class.getSimpleName());
        for (String[] filed : itemList) {
            if (ArrayUtils.isEmpty(filed) || filed.length < 3 || StringUtils.isEmpty(filed[1])) {
                continue;
            }
            /*if (StringUtils.isNotEmpty(filed[2])) {
                System.out.println("*//**");
             System.out.println("*" + filed[2]);
             System.out.println("*//*");
            }*/
            System.out.println("private " + filed[0] + " " + filed[1] + ";//" + filed[2]);
        }

        System.out.println();
        System.out.println("//************* set get 构造方法 ******************");
        for (String[] filed : itemList) {
            if (ArrayUtils.isEmpty(filed) || filed.length < 3 || StringUtils.isEmpty(filed[1])) {
                continue;
            }
            if (filed.length > 3 && StringUtils.isNotEmpty(filed[3])) {
                System.out.println("@Column(name = \"" + camelToUnderline(filed[1]) + "\")");
                if (!baseType.contains(filed[0])) {
                    System.out.println("@Enumerated(EnumType.STRING)");
                }
            }
            System.out.println("public " + filed[0] + " get" + (filed[1].substring(0, 1).toUpperCase() + filed[1].substring(1)) + "() {");
            System.out.println("    return " + filed[1] + " ;");
            System.out.println("}");
            System.out.println();
            System.out.println("public void set" + (filed[1].substring(0, 1).toUpperCase() + filed[1].substring(1)) + "(" + filed[0] + " " + filed[1] + ") {");
            System.out.println("    this." + filed[1] + " = " + filed[1] + " ;");
            System.out.println("}");
            System.out.println();
        }
        System.out.println("//************* JPA-XML ******************");
        String userName = System.getenv().get("USERNAME");
        String tableName = camelToUnderline(clazz == null ? "table_name" : clazz.getSimpleName());
        System.out.println("<changeSet author=\"" + userName + "\" id=\"" + tableName + "_" + userName + "_1\">");
        System.out.println("<createTable tableName=\"" + tableName + "\">");
        System.out.println("<column name=\"id\" type=\"bigint\" autoIncrement=\"true\" startWith=\"1\">");
        System.out.println("<constraints nullable=\"false\" primaryKey=\"true\" primaryKeyName=\"pk_" + tableName + "\"/>");
        System.out.println("</column>");
        for (String[] filed : itemList) {
            if (filed.length > 3 && StringUtils.isEmpty(filed[3])) {
                continue;
            }
            StringBuilder sb = new StringBuilder();
            sb.append("<column name=\"").append(camelToUnderline(filed[1])).append("\" type=\"").append(filed[3]).append("\"");
            if (filed.length > 2 && StringUtils.isNotEmpty(filed[2])) {
                sb.append(" remarks=\"").append(filed[2]).append("\"");
            }
            if (filed.length > 4 && StringUtils.isNotEmpty(filed[4])) {
                sb.append(" defaultValue=\"").append(filed[4]).append("\"");
            }
            sb.append("/>");
            System.out.println(sb.toString());
        }
        System.out.println(" <column name=\"creater\" type=\"varchar(50)\">\n" +
                " <constraints nullable=\"false\"/>\n" +
                " </column>\n" +
                " <column name=\"create_time\" type=\"bigint\">\n" +
                " <constraints nullable=\"false\"/>\n" +
                " </column>\n" +
                " <column name=\"modifier\" type=\"varchar(50)\">\n" +
                " <constraints nullable=\"false\"/>\n" +
                " </column>\n" +
                " <column name=\"modify_time\" type=\"bigint\">\n" +
                " <constraints nullable=\"false\"/>\n" +
                " </column>\n" +
                " <column name=\"version\" type=\"bigint\">\n" +
                " <constraints nullable=\"false\"/>\n" +
                " </column>\n" +
                " </createTable>\n" +
                "</changeSet>");
    }

    public static final char UNDERLINE = '_';

    //驼峰命名转下划线命名 camelName -> camel_name
    public static String camelToUnderline(String param) {
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = param.charAt(i);
            if (Character.isUpperCase(c)) {
                if (sb.length() > 0) {
                    sb.append(UNDERLINE);
                }

                sb.append(Character.toLowerCase(c));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    //下划线命名转驼峰命名 camel_name -> camelName
    public static String underlineToCamel(String param) {
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = param.charAt(i);
            if (c == UNDERLINE) {
                if (++i < len) {
                    sb.append(Character.toUpperCase(param.charAt(i)));
                }
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    //下划线命名转驼峰命名 camel_name -> camelName
    public static String underlineToCamel2(String param) {
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        StringBuilder sb = new StringBuilder(param);
        Matcher mc = Pattern.compile("_").matcher(param);
        int i = 0;
        while (mc.find()) {
            int position = mc.end() - (i++);
            sb.replace(position - 1, position + 1, sb.substring(position, position + 1).toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 生成导出excel方法的static方法
     *
     * @param filePath
     */
    public static void generateExportStatic(String filePath) {
        try {
            /*List<String[]> itemList = ExcelUtil.importExcelFromPath(filePath, 1, -1);
            System.out.println();
            System.out.println("/*//************* static{}方法 ******************");
             System.out.println("DEFAULT_FIELDS = new ArrayList<>();");
             for (String[] filed : itemList) {
             System.out.println("DEFAULT_FIELDS.add(\"" + filed[1] + "\");");
             }
             System.out.println();
             System.out.println("DEFAULT_FIELD_HEADER_MAP = new HashMap<>();");
             for (String[] filed : itemList) {
             System.out.println("DEFAULT_FIELD_HEADER_MAP.put(\"" + filed[1] + "\",\"" + filed[2] + "\");");
             }
             System.out.println();*/
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String getSystemClipboard() {//获取系统剪切板的文本内容[如果系统剪切板复制的内容是文本]
        Clipboard sysClb = null;
        sysClb = Toolkit.getDefaultToolkit().getSystemClipboard();
        Transferable t = sysClb.getContents(null);
        //Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);  //跟上面三行代码一样
        try {
            if (null != t && t.isDataFlavorSupported(DataFlavor.stringFlavor)) {
                String text = (String) t.getTransferData(DataFlavor.stringFlavor);
                return text;
            }
        } catch (UnsupportedFlavorException e) {
            //System.out.println("Error tip: "+e.getMessage());
        } catch (IOException e) {
        }    //System.out.println("Error tip: "+e.getMessage());
        return null;
    }

    public static void printToDTO(List<String[]> itemList, Class clazz, boolean hasNew) {
        System.out.println("--------toDTO------------------------------");
        if (hasNew) {
            String cName = clazz.getSimpleName();
            String newStr = cName + "DTO dto = new " + cName + "DTO();";
            System.out.println(newStr);
            System.out.println("");
        }

        for (String[] strs : itemList) {
            String fieldName = strs[1];
            try {
                fieldName = fieldName.replaceFirst(fieldName.substring(0, 1), fieldName.substring(0, 1).toUpperCase());
            } catch (Exception e) {
                System.out.println("null");
            }
            String setStr = "dto.set" + fieldName + "(this.get" + fieldName + "());";
            System.out.println(setStr);
        }
    }

    public static void printFromDTO(List<String[]> itemList, Class clazz) {
        System.out.println("--------fromDTO------------------------------");
        for (String[] strs : itemList) {
            String fieldName = strs[1];
            fieldName = fieldName.replaceFirst(fieldName.substring(0, 1), fieldName.substring(0, 1).toUpperCase());
            String setStr = "this.set" + fieldName + "(dto.get" + fieldName + "());";
            System.out.println(setStr);
        }
    }

    //生成插入权限资源的sql，实际执行的时候，excel需要是03版本，且先配好模块。
    public static void generatePrivilegeSqlFromExcel(String filePath) {
        try {
            InputStream is = null;
            is = new FileInputStream(filePath);
            List<String[]> itemList = ExcelUtil.importExcel(new BufferedInputStream(is), 1, 1);
            String sqlTempStr = "INSERT INTO `sys_privilege` ( `creater`, `create_time`, `modifier`, `modify_time`, `version`, `domain`, `module_id`, `type`, `key`, `uri`, `name`, `description`, `status`, `related_menu_key` ) " +
                    "SELECT " +
                    "'admin', " +
                    "UNIX_TIMESTAMP() * 1000," +
                    "'admin', " +
                    "UNIX_TIMESTAMP() * 1000, " +
                    "0, " +
                    "@domainName, " +
                    "(SELECT sm.id FROM sys_module sm WHERE sm.`name` = @moduleName AND sm.domain = @domainName), " +
                    "@privilegeResourceType, " +
                    "@key, " +
                    "@uri, " +
                    "@name, " +
                    "NULL, " +
                    "'ENABLED', " +
                    "@relatedMenuKey " +
                    "FROM sys_privilege s1 WHERE NOT EXISTS (SELECT s2.id FROM sys_privilege s2 WHERE s2.`key` = @key ) LIMIT 1;";
            Map<String, String> privilegeResourceTypeNameMap = new HashMap<>();
            for (PrivilegeResourceType privilegeResourceType : PrivilegeResourceType.values()) {
                privilegeResourceTypeNameMap.put(privilegeResourceType.getName(), privilegeResourceType.toString());
            }

            Map<String, String> domainNameMap = new HashMap<>();
            /*for (SystemDomain systemDomain : SystemDomain.values()) {
                domainNameMap.put(systemDomain.getName(), systemDomain.toString());
            }*/
            for (String[] privilegeInfo : itemList) {
                if (ArrayUtils.isNotEmpty(privilegeInfo) && privilegeInfo.length >= 6) {
                    if (!SysUtil.isAllNotEmpty(privilegeInfo[0], privilegeInfo[1], privilegeInfo[2], privilegeInfo[3], privilegeInfo[4], privilegeInfo[5])) {
                        continue;
                    }
                    Map<String, String> privilegeInfoMap = new HashMap<>();
                    String name = privilegeInfo[0].trim();
                    String privilegeResourceType = privilegeResourceTypeNameMap.get(privilegeInfo[1].trim());
                    String key = privilegeInfo[2].trim();
                    String uri = privilegeInfo[3].trim();
                    String domainName = domainNameMap.get(privilegeInfo[4].trim());
                    String moduleName = privilegeInfo[5].trim();
                    String relatedMenuKey = null;
                    if (privilegeInfo.length >= 9 && StringUtils.isNotEmpty(privilegeInfo[8].trim())) {
                        relatedMenuKey = privilegeInfo[8].trim();
                    }

                    privilegeInfoMap.put("name", name);
                    privilegeInfoMap.put("privilegeResourceType", privilegeResourceType);
                    privilegeInfoMap.put("key", key);
                    privilegeInfoMap.put("uri", uri);
                    privilegeInfoMap.put("domainName", domainName);
                    privilegeInfoMap.put("moduleName", moduleName);
                    privilegeInfoMap.put("relatedMenuKey", relatedMenuKey);
                    String resultSql = sqlTempStr;
                    for (String replaceKey : privilegeInfoMap.keySet()) {
                        resultSql = resultSql.replaceAll("@" + replaceKey, StringUtils.isNotEmpty(privilegeInfoMap.get(replaceKey)) ? "'" + privilegeInfoMap.get(replaceKey).replaceAll("(\t\r\n)$", "") + "'" : "NULL");
                    }
                    System.out.println(resultSql);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    public static void main(String[] args) {
//        CodeTemplateUtil.generateEntityFromClass(Carrier.class);
//        generatePrivilegeSqlFromExcel("C:\\Users\\xinyu.qiu\\Desktop\\发布流程\\菜单权限配置模板.xls");
    }

}
